package com.dianxin.farm.api;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dianxin.farm.config.MyWxPayConfig;
import com.dianxin.farm.entity.*;
import com.dianxin.farm.filter.AuthorCheck;
import com.dianxin.farm.mapper.bill.ShareBillMapper;
import com.dianxin.farm.mapper.customer.CustomerBalanceMapper;
import com.dianxin.farm.mapper.customer.CustomerInfoMapper;
import com.dianxin.farm.mapper.customer.EnterpriseBalanceHistoryMapper;
import com.dianxin.farm.mapper.customer.EnterpriseInfoMapper;
import com.dianxin.farm.mapper.goods.GoodsInfoMapper;
import com.dianxin.farm.request.pay.OrderIdRequest;
import com.dianxin.farm.service.CurrentLoginService;
import com.dianxin.farm.service.IOrderBillService;
import com.dianxin.farm.util.exception.UserOperationException;
import com.dianxin.farm.util.order.Generator;
import com.dianxin.farm.util.order.IdGeneratorFactory;
import com.dianxin.farm.util.util.Assert;
import com.dianxin.farm.util.util.DateUtil;
import com.dianxin.farm.util.util.HttpUtil;
import com.dianxin.farm.util.util.IpUtil;
import com.dianxin.farm.util.web.ApiResponse;
import com.dianxin.farm.util.web.ApiResponseUtils;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

import static com.dianxin.farm.util.wx.WeiXinUtil.buildRandom;
import static com.dianxin.farm.util.wx.WeiXinUtil.getCurrTime;
import static com.github.wxpay.sdk.WXPayConstants.SUCCESS;


/**
 * @auther xukai
 * @date 2020/9/27.
 */

@Controller
@RequestMapping(value = "/pay", method = RequestMethod.POST, produces = "application/json;charset=utf-8")
@Api(description = "支付接口")
@AuthorCheck
public class WxController {

    @Value("${appSecret}")
    private String appSecret;

    private static Logger logger = LoggerFactory.getLogger(WxController.class);

    private Generator generator = IdGeneratorFactory.create("wx_bill");
    @Resource
    private MyWxPayConfig config;
    @Resource
    private IOrderBillService orderBillService;
    @Resource
    private WxPayService wxPayService;
    @Resource
    private CurrentLoginService currentLoginService;
    @Resource
    private EnterpriseInfoMapper enterpriseInfoMapper;
    @Resource
    private CustomerBalanceMapper customerBalanceMapper;
    @Resource
    private ShareBillMapper shareBillMapper;
    @Resource
    private GoodsInfoMapper goodsInfoMapper;
    @Resource
    private CustomerInfoMapper customerInfoMapper;
    @Resource
    private EnterpriseBalanceHistoryMapper enterpriseBalanceHistoryMapper;

    private static String host = "http://www.gaojiazhuang.shop:9001";

    // "http://www.huozhe666.com:8093";


    @RequestMapping(value = "/wxUnifiedorder", method = RequestMethod.POST)
    @ApiOperation("生成统一支付信息")
    @Transactional
    @ResponseBody
    public ApiResponse wxUnifiedorder(HttpServletRequest servletRequest, @RequestBody OrderIdRequest request) {

        Map<String, String> result = new HashMap<>();

        //获取当前用户的openId
        CustomerInfo customerInfo = currentLoginService.getCurrentInfo();
        String openId = customerInfo.getOpenId();


        Integer orderBillId = request.getId();
        OrderBill orderBill1 = orderBillService.getById(orderBillId);
        if (orderBill1 == null || orderBill1.getStatus() != 0) {
            throw new UserOperationException("订单状态异常，或者订单不存在");
        }

        //钱币单位分
        BigDecimal orderPrice = orderBill1.getOrderPrice();
        //微信支付单位为分，转化扩大一百倍
        String totalPrice = orderPrice.movePointRight(2).toString();

        String userIp = IpUtil.getIP(servletRequest);
        WXPay wxPay = new WXPay(config);
        SortedMap<String, String> params = new TreeMap<>();
        params.put("device_info", "WEB"); //设备号
        params.put("body", "商品描述");//商品描述
        //生成商户订单号
        Long serialNumMax = generator.generate();//redisUtil.incr("outTradeNo");
        String outTradeNo = orderBill1.getOrderNo();

        params.put("out_trade_no", outTradeNo);
        params.put("total_fee", totalPrice);
//        params.put("time_start", time_start);
        params.put("trade_type", "JSAPI");
        params.put("notify_url", host + "/pay/callBack");
        params.put("spbill_create_ip", userIp);
        params.put("openid", openId);
        Map<String, String> resultMap = null;
        Map<String, String> responseMap = new HashMap<>();
        try {

         /*   "\"nonce_str\":\"CLmTzhlRYy3E7Sg9\",\"device_info\":\"WEB\",\"appid\":\"wx277402b1f5686d6e\",\"sign\":\"0C5C11253F2075D9282952DAA35A4FAF\",\"err_code\":\"ORDERPAID\",\"return_msg\":\"OK\",\"result_code\":\"FAIL\",\"err_code_des\":\"该订单已支付\",\"mch_id\":\"1600943280\",\"return_code\":\"SUCCESS\"}\n"*/
            resultMap = wxPay.unifiedOrder(params);

            //获取返回码
            //若返回码为SUCCESS，则会返回一个result_code,再对该result_code进行判断
            //{"return_code":"FAIL","return_msg":"invalid total_fee"}
        } catch (Exception e) {
            logger.error("生成统一支付信息失败", e);
            return ApiResponseUtils.failure();
        }

        Object o = JSONObject.toJSON(resultMap);

        System.out.println("微信支获取预支付信息成功, 返回值 response={}" + o);
        String returnCode = resultMap.get("return_code");
        if (!SUCCESS.equals(returnCode)) {
            logger.error("returnCode异常()：" + returnCode);
            return ApiResponseUtils.failure("returnCode异常()：" + returnCode);
        }
        String resultCode = resultMap.get("result_code");
        if (!SUCCESS.equals(resultCode)) {
            logger.error("resultCode异常()：" + resultCode + "{}" + resultMap.get("err_code_des"));
            return ApiResponseUtils.failure(resultMap.get("err_code_des"));
        }
        String prepay_id = resultMap.get("prepay_id");
        if (prepay_id == null) {
            logger.error("获取预支付id异常()：" + prepay_id);
            return ApiResponseUtils.failure("获取预支付id异常()：" + prepay_id);
        }
/*

        String sign=resultMap.get("sign");
        String nonceStr=resultMap.get("nonce_str");
*/

        // ******************************************
        //
        //  前端调起微信支付必要参数
        //
        // ******************************************
        String packages = "prepay_id=" + prepay_id;
        Map<String, String> wxPayMap = new HashMap<>();
        wxPayMap.put("appId", config.getAppID());
        wxPayMap.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000L));
        wxPayMap.put("nonceStr", String.valueOf(System.currentTimeMillis()));
        wxPayMap.put("package", packages);
        wxPayMap.put("signType", "MD5");
        // 加密串中包括 appId timeStamp nonceStr package signType 5个参数, 通过sdk WXPayUtil类加密, 注意, 此处使用  MD5加密  方式
        String sign = null;
        try {
            sign = WXPayUtil.generateSignature(wxPayMap, config.getKey());
        } catch (Exception e) {
            System.out.println("签名失败" + e);
        }

        // ******************************************
        //
        //  返回给前端调起微信支付的必要参数
        //
        // ******************************************
        result.put("prepay_id", prepay_id);
        result.put("sign", sign);
        result.putAll(wxPayMap);

        //保存该订单记录
        return ApiResponseUtils.success(result);
    }


    @RequestMapping(value = "/callBack", method = RequestMethod.POST)
    @ApiOperation("支付回调地址")
    @AuthorCheck(authorCheck = false)
    @ResponseBody
    @Transactional
    public String callBack(HttpServletRequest request, HttpServletResponse response,
                           @RequestBody String xmlData) {

        try {
            Map<String, String> map = WXPayUtil.xmlToMap(xmlData);
            boolean sign = WXPayUtil.isSignatureValid(map, config.getKey());
            if (sign) {
                String wxouttradeno = map.get("out_trade_no");
                String wxappid = map.get("appid");
                String wxmchid = map.get("mch_id");
                String wxbanktype = map.get("bank_type");
                String wxcashfee = map.get("cash_fee");
                String wxtotalfee = map.get("total_fee");
                String wxissubscribe = map.get("is_subscribe");
                String wxopenid = map.get("openid");
                String wxtimeend = map.get("time_end");
                String wxtradetype = map.get("trade_type");
                String wxtransactionid = map.get("transaction_id");

//"===========支付回调===========
                // 商户订单号:20100301834950020 ,APPID:wx277402b1f5686d6e ,商户ID:1600943280,付款银行:OTHERS
                //现金支付金额:13 订单金额:13
                //是否关注公众账号:Y
                //用户标识:oFhzs1P4a43tqTL35JO5_XZ0Ee8Q
                // 支付完成时间:20201008100747
                //交易类型:JSAPI
                //微信支付订单号:4200000690202010085062945345
                System.out.println("===========支付回调===========");
                System.out.println("商户订单号:" + wxouttradeno);
                System.out.println("APPID:" + wxappid);
                System.out.println("商户ID:" + wxmchid);
                System.out.println("付款银行:" + wxbanktype);
                System.out.println("现金支付金额:" + wxcashfee);
                System.out.println("订单金额:" + wxtotalfee);
                System.out.println("是否关注公众账号:" + wxissubscribe);
                System.out.println("用户标识:" + wxopenid);
                System.out.println("支付完成时间:" + wxtimeend);
                System.out.println("交易类型:" + wxtradetype);  // JSAPI、NATIVE、APP
                System.out.println("微信支付订单号:" + wxtransactionid);

                QueryWrapper queryWrapper = new QueryWrapper();
                queryWrapper.eq("order_no", wxouttradeno);

                OrderBill orderBill = orderBillService.getOne(queryWrapper);
                orderBill.setStatus(1);
                orderBill.setWxNo(wxtransactionid);
                Date payTime = DateUtil.fromString(wxtimeend, "yyyyMMddHHmmss");//20201008100747
                ZoneId zoneId = ZoneId.systemDefault();
                orderBill.setPayTime(LocalDateTime.ofInstant(payTime.toInstant(), zoneId));
                BigDecimal orderMoney=orderBill.getOrderPrice();//支付金额
                logger.info("{}订单金额:"+orderMoney);
                Integer goodsInfoId=orderBill.getGoodsInfoId();
                GoodsInfo goodsInfo=goodsInfoMapper.selectById(goodsInfoId);//订单的套餐信息

                //计算分红金额
                BigDecimal devideRate=goodsInfo.getDevidendRate();
                BigDecimal profitRate=goodsInfo.getProfitRate();
                BigDecimal devideMoney=orderMoney.multiply(devideRate).multiply(profitRate);
                devideMoney=devideMoney.divide(new BigDecimal("10000"),BigDecimal.ROUND_HALF_UP);
                logger.info("{}分红金额:"+devideMoney);



                //企业账分红1、企业账户增加金额  2、股东账户增加分红，3记录分红记录
                //1
                enterpriseInfoMapper.selectForUpdate(26);
                enterpriseInfoMapper.editBalance(26,orderMoney);
                EnterpriseBalanceHistory enterpriseBalanceHistory=new EnterpriseBalanceHistory();
                enterpriseBalanceHistory.setCreateTime(LocalDateTime.now());
                enterpriseBalanceHistory.setMoney(orderMoney);
                enterpriseBalanceHistory.setOrderId(orderBill.getId());
                enterpriseBalanceHistory.setEnterpriseId(26);
                enterpriseBalanceHistory.setType(1);
                enterpriseBalanceHistoryMapper.insert(enterpriseBalanceHistory);

                //2
                Integer customerId=orderBill.getCustomerId();
                Integer devideCustomerId = 0;
                CustomerInfo customerInfo=customerInfoMapper.selectById(customerId);
                Integer role=customerInfo.getRole();
                if (role==0){
                    devideCustomerId=customerInfo.getParentId();
                }
                if (role==1){
                    devideCustomerId=customerId;
                }
                customerBalanceMapper.selectForUpdate(devideCustomerId);
                customerBalanceMapper.addBalance(devideCustomerId,devideMoney);

                //3
                ShareBill shareBill=new ShareBill();
                shareBill.setCreateTime(LocalDateTime.now());
                shareBill.setBillCode(generator.generate());
                shareBill.setOrderId(orderBill.getId());
                shareBill.setCustomerId(customerId);
                shareBillMapper.insert(shareBill);

                orderBillService.updateById(orderBill);
                logger.info("回调订单完成");
            }

        } catch (Exception e) {
            logger.info("参数解析异常", e);
        }


        StringBuilder sb = new StringBuilder();
        sb.append("<xml>");
        sb.append("<return_code><![CDATA[SUCCESS]]></return_code>");
        sb.append("<return_msg><![CDATA[OK]]></return_msg>");
        sb.append("</xml>");
        logger.info("通知微信成功");
        return sb.toString();
    }



    private static String jsToken = null;

    private static String byteToStr(byte[] byteArray) {
        String strDigest = "";
        for (int i = 0; i < byteArray.length; i++) {
            strDigest += byteToHexStr(byteArray[i]);
        }
        return strDigest;
    }

    private static String byteToHexStr(byte mByte) {
        char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
        char[] tempArr = new char[2];
        tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
        tempArr[1] = Digit[mByte & 0X0F];

        String s = new String(tempArr);
        return s;
    }

    /**
     * 生成随机字符串
     */
    public static String getNonceStr() {
        String currTime = getCurrTime();
        String strTime = currTime.substring(8, currTime.length());
        String strRandom = buildRandom(4) + "";
        return strTime + strRandom;
    }


    @RequestMapping(value = "/getSdkConfig")
    @ResponseBody
    @ApiOperation("获取jsapi封装参数")
    public ApiResponse<Map<String,String>> getSdkConfig(@RequestParam("url")String url) {
        Assert.notNull(url,"检查参数");

        System.out.println("调用url==={}"+url);
        String accessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
        accessTokenUrl=accessTokenUrl.replace("APPID",config.getAppID());
        accessTokenUrl=accessTokenUrl.replace("APPSECRET",appSecret);
        System.out.println("accessTokenUrl===="+accessTokenUrl);
        String accessTokenResult = HttpUtil.doGet(accessTokenUrl);
        JSONObject accessJsonObject = JSONObject.parseObject(accessTokenResult);
        String accessToken = accessJsonObject.getString("access_token");

        String jsTokenUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
        String jsTokenResult =  HttpUtil.doGet(jsTokenUrl.replace("ACCESS_TOKEN", accessToken));

        JSONObject jsTokenJsonObject = JSONObject.parseObject(jsTokenResult);

        if (jsTokenJsonObject != null) {
            int errcode = jsTokenJsonObject.getInteger("errcode");
            if (errcode == 0) {
                jsToken = jsTokenJsonObject.getString("ticket");
            }
        }

       // String url = "http://www.huozhe666.com/phone";//因为要使用微信客户微访问本地环境，这里面使用了花生壳做内网映射
        String timestamp = String.valueOf(new Date().getTime() / 1000);
        String noncestr = getNonceStr();
        String jsapi_ticket = jsToken;

        String str1 = "noncestr=" + noncestr;
        String str2 = "jsapi_ticket=" + jsapi_ticket;
        String str3 = "timestamp=" + timestamp;
        String str4 = "url=" + url;

        String[] paramArr = new String[] { str1, str2, str3, str4 };
        Arrays.sort(paramArr);

        // 将排序后的结果拼接成一个字符串
        String content = paramArr[0].concat("&").concat(paramArr[1]).concat("&").concat(paramArr[2]).concat("&").concat(paramArr[3]);
        String signature = null;
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            // 对接后的字符串进行sha1加密
            byte[] digest = md.digest(content.toString().getBytes());
            signature = byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

		/*appId: '', // 必填，公众号的唯一标识
	    timestamp: , // 必填，生成签名的时间戳
	    nonceStr: '', // 必填，生成签名的随机串
	    signature: '',// 必填，签名
	    jsApiList: [] // 必填，需要使用的JS接口列表
*/

		Map<String,String> map=new HashMap<>();
        map.put("appId", config.getAppID());
        map.put("timestamp", timestamp);
        map.put("nonceStr", noncestr);
        map.put("signature", signature);
        return ApiResponseUtils.success(map);
    }


}
